/*
** Label.c
** handle system, user and code labels
*/

#include "dis6502.h"

#define LABEL_MEM_SIZE (MAX_BUF_LABEL + 32)

static char szEquPath[_MAX_PATH];

static char *LabelFindEquateInArray(char *EquArray, WORD wAddr, LABEL_FLAG *bFlag)
{
WORD iArray;
WORD wLen;
char *p;

     if ((p = EquArray) == NULL)
          return NULL;
     iArray = 0;
     while ((iArray < MAX_BUF_LABEL) && (*((WORD *) p)))
          {
          if (*((WORD *) p) == wAddr)
               {
               *bFlag = (BOOL) *(p + 2);
               return p + 3;
               }
          wLen = strlen(p + 3) + 3 + 1;
          iArray += wLen;
          p += wLen;
          }
     return NULL;
}

static char *LabelReserveEquateInArray(char *EquArray, WORD wAddr, LABEL_FLAG bFlag)
{
WORD iArray;
WORD wLen;
char *p;

     if ((p = EquArray) == NULL)
          return NULL;
     iArray = 0;
     while ((iArray < MAX_BUF_LABEL) && (*((WORD *) p)))
          {
          if (*((WORD *) p) == wAddr)
               {
               *(p + 2) = (char) bFlag;
               return p + 3;
               }
          wLen = strlen(p + 3) + 3 + 1;
          iArray += wLen;
          p += wLen;
          }
     return NULL;
}

char *LabelFindEquate(WORD wAddr, LABEL_FLAG *bFlag)
{
char *lpLabel;

     if (lpLabel = LabelFindEquateInArray(lpLabelUser, wAddr, bFlag))
          return lpLabel;
     return LabelFindEquateInArray(lpLabelSystem, wAddr, bFlag);
}

/*
** set flag for all user labels
*/
void LabelUserSetFlag(LABEL_FLAG bFlag)
{
WORD iArray;
WORD wLen;
char *p;

     if ((p = lpLabelUser) == 0)
          return;
     iArray = 0;
     while ((iArray < MAX_BUF_LABEL) && (*((WORD *) p)))
          {
          *(p + 2) = (char) bFlag;
          wLen = strlen(p + 3) + 3 + 1;
          iArray += wLen;
          p += wLen;
          }
}

static BOOL LabelAddEquate(HWND hWnd, char *szFileName, char *EquArray, char *szLabel, WORD wAddr, LABEL_ENUM wLabelType)
{
WORD iArray;

     if (EquArray == NULL)
          return FALSE;
     iArray = 0;
     while (iArray < MAX_BUF_LABEL)
          {
          if (*((WORD *) (EquArray + iArray)))
               {
               if (*((WORD *) (EquArray + iArray)) == wAddr)
                    {
                    Error(hWnd, IDS_ERR_DUP_ADDR,
                          "Address $%04X is defined twice (labels %s and %s) in file %s",
                          wAddr, EquArray + iArray + 2, szLabel, szFileName);
                    return FALSE;
                    }
               iArray += 3;
               if (! strcmp(EquArray + iArray, szLabel))
                    {
                    Error(hWnd, IDS_ERR_DUP_LABEL, "Label %s is defined twice in file %s", szLabel, szFileName);
                    return FALSE;
                    }
               iArray += strlen(EquArray + iArray) + 1;
               }
          else {

               /*
               ** Add label definition to the label buffer.
               */
               *((WORD *) (EquArray + iArray)) = wAddr;
               iArray += 2;
               *((char *) (EquArray + iArray)) = LABEL_FLAG_UNREFERENCED;
               iArray++;
               strcpy(EquArray + iArray, szLabel);
               iArray += strlen(szLabel) + 1;
               *((WORD *) (EquArray + iArray)) = 0;

               /*
               ** Add this line to disassembly listing only if it is a label definition
               ** (the lines LABEL+1=$0251) are ignored).
               */
               if ((strchr(szLabel, '+') == NULL) && (strchr(szLabel, '-') == NULL))
                    if (! DisAddLabel(hWnd, szLabel, wAddr, wLabelType))
                         break;
               return TRUE;
               }
          }
     Error(hWnd, IDS_ERR_LABEL_OVEFLOW, "Label overflow (too many labels) !");
     return FALSE;
}

static BOOL LabelLoadEquates(HWND hWnd, char *szFileName, char *EquArray, LABEL_ENUM wLabelType)
{
FILE *fd;
char szBuf[120];
char szLabelName[40];
WORD wLabelAddr;
char *p;
int iIndex;
BOOL bEqu;
BOOL bErr;

     if (EquArray == NULL)
          return FALSE;

     /*
     ** open filename.
     */
     if ((fd = fopen(szFileName, "rt")) == NULL)
          {
          bErr = TRUE;
          GetModuleFileName(hInst, szBuf, sizeof(szBuf) - strlen(szFileName));
          if (p = strrchr(szBuf, '\\'))
               {
               strcpy(p + 1, szFileName);
               if (fd = fopen(szBuf, "rt"))
                    bErr = FALSE;
               }
          if (bErr)
               {
               Error(hWnd, IDS_ERR_OPENING_EQU_FILE, "Error while opening equate file %s", szFileName);
               return FALSE;
               }
          }

     /*
     ** read file and parse string
     */
     while (fgets(szBuf, sizeof(szBuf), fd))
          {
          if ((strlen(szBuf)) && (szBuf[strlen(szBuf) - 1] == '\n'))
               szBuf[strlen(szBuf) - 1] = 0;

          /*
          ** skip line number if exist
          */
          szLabelName[0] = 0;
          wLabelAddr = 0;
          p = szBuf;
          while (isdigit(*p))
               p++;

          /*
          ** skip blanks
          */
          while (isspace(*p))
               p++;

          /*
          ** if we have a comment, we add it to the disassembly listing.
          */
          if (*p == ';')
               {

               /*
               ** skip blanks
               */
               p++;
               while (isspace(*p))
                    p++;

               /*
               ** save comment
               */
               DisAddComment(hWnd, p, wLabelType);
               continue;
               }

          /*
          ** we must have a label name
          */
          if (! isalpha(*p))
               continue;

          /*
          ** save label name
          */
          szLabelName[0] = *p++;
          iIndex = 1;
          while ((*p && (*p != '=') && (*p != '#')) && (iIndex < sizeof(szLabelName) - 1))
               szLabelName[iIndex++] = *p++;
          szLabelName[iIndex] = 0;

          /*
          ** now we must have an equal (= or #) sign
          */
          if ((*p != '=') && (*p != '#'))
               continue;
          bEqu = (*p++ == '#');

          /*
          ** remove trailing spaces
          */
          iIndex = strlen(szLabelName);
          while (iIndex && isspace(szLabelName[iIndex - 1]))
               szLabelName[--iIndex] = 0;

          /*
          ** skip blanks
          */
          while (isspace(*p))
               p++;

          /*
          ** now we must have an address (hex or dec)
          */
          if (*p == '$')
               sscanf(p + 1, "%x", &wLabelAddr);
          else sscanf(p + 1, "%d", &wLabelAddr);

          /*
          ** save definition
          */
          if (bEqu)
               {

               /*
               ** This label is not an address but a value. It is not added to the label
               ** array (which contains addresses) but it must appear in the disassembly listing.
               */
               if (! DisAddLabel(hWnd, szLabelName, wLabelAddr, wLabelType))
                    break;
               }
          else {

               /*
               ** store label and address into array.
               */
               if (wLabelAddr)
                    if (LabelAddEquate(hWnd, szFileName, EquArray, szLabelName, wLabelAddr, wLabelType) == FALSE)
                         break;
               }
          }
     fclose(fd);

     /*
     ** check if there is at least one label defined...
     */
     if (! (*((WORD *) EquArray)))
          {
          Error(hWnd, IDS_ERR_NO_LABEL, "No label found in file %s", szFileName);
          return FALSE;
          }
     return TRUE;
}

BOOL __export CALLBACK LabelLoadProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
     switch (message)
          {
          case WM_INITDIALOG:
               PostMessage(hDlg, WM_USER + 1234, 0, 0L);
               return TRUE;

          case WM_USER + 1234:
               if (lpLabelSystem = (char *) MemoryAlloc(LABEL_MEM_SIZE))
                    {
                    if (! LabelLoadEquates(hDlg, szComputerEqu, lpLabelSystem, LABEL_SYSTEM))
                         {
                         MemoryFree(lpLabelSystem);
                         lpLabelSystem = NULL;
                         }
                    }
               else Error(hDlg, IDS_ERR_NO_LABEL_MEMORY, "Could not allocate memory for equates !");
               EndDialog(hDlg, TRUE);
               return TRUE;
          }
     return FALSE;
}

BOOL __export CALLBACK LabelUserLoadProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
     switch (message)
          {
          case WM_INITDIALOG:
               PostMessage(hDlg, WM_USER + 2345, 0, 0L);
               return TRUE;

          case WM_USER + 2345:
               if (lpLabelUser = (char *) MemoryAlloc(LABEL_MEM_SIZE))
                    {
                    if (! LabelLoadEquates(hDlg, szEquPath, lpLabelUser, LABEL_USER))
                         {
                         MemoryFree(lpLabelUser);
                         lpLabelUser = NULL;
                         }
                    }
               else Error(hDlg, IDS_ERR_NO_LABEL_MEMORY, "Could not allocate memory for equates !");
               EndDialog(hDlg, TRUE);
               return TRUE;
          }
     return FALSE;
}

static int LabelFillListbox(HWND hList)
{
WORD iArray;
WORD wLen;
char *p;
char szBuf[128];
int nb = 0;

     SendMessage(hList, LB_RESETCONTENT, 0, 0L);
     if ((p = lpLabelUser) == 0)
          return 0;
     iArray = 0;
     while ((iArray < MAX_BUF_LABEL) && (*((WORD *) p)))
          {
          wsprintf(szBuf, "%04X\t%s", *((WORD *) p), p + 3);
          SendMessage(hList, LB_ADDSTRING, 0, (LPARAM) (LPCSTR) szBuf);
          wLen = strlen(p + 3) + 3 + 1;
          iArray += wLen;
          p += wLen;
          nb++;
          }
     return nb;
}

static int LabelExist(HWND hDlg, char *szAddr)
{
int iNbItem, iItem;
char szBuf[128];

     iNbItem = (int) SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETCOUNT, 0, 0);
     for (iItem = iNbItem - 1; iItem >= 0; iItem--)
          {
          SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETTEXT, iItem, (LPARAM) (LPCSTR) szBuf);
          if (! strncmp(szAddr, szBuf, 5))
               return iItem;
          }
     return -1;
}

BOOL __export CALLBACK LabelUserEditProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
BOOL bSelected;
int iNbItem, iItem;
WORD wAddr;
char szText[32];
char szBuf[128];
WORD iArray;
char *lpLabel;

     switch (message)
          {
          case WM_INITDIALOG:
               LabelFillListbox(GetDlgItem(hDlg, IDC_LIST_LABEL));
               EnableWindow(GetDlgItem(hDlg, IDC_DELETELABEL), FALSE);
               EnableWindow(GetDlgItem(hDlg, IDC_ADDLABEL), FALSE);
               SendDlgItemMessage(hDlg, IDC_LABELADDR, EM_LIMITTEXT, 4, 0L);
               SendDlgItemMessage(hDlg, IDC_LABELTEXT, EM_LIMITTEXT, 20, 0L);
               return TRUE;

          case WM_COMMAND:
               switch (wParam)
                    {
                    case IDC_LIST_LABEL:
                         iNbItem = (int) SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETCOUNT, 0, 0);
                         if (HIWORD(lParam) == LBN_SELCHANGE)
                              {
                              bSelected = FALSE;
                              for (iItem = 0; iItem < iNbItem; iItem++)
                                   if (SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETSEL, iItem, 0))
                                        {
                                        SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETTEXT, iItem, (LPARAM) (LPCSTR) szBuf);
                                        szBuf[4] = 0;
                                        SetDlgItemText(hDlg, IDC_LABELADDR, szBuf);
                                        SetDlgItemText(hDlg, IDC_LABELTEXT, szBuf + 5);
                                        bSelected = TRUE;
                                        break;
                                        }
                              EnableWindow(GetDlgItem(hDlg, IDC_DELETELABEL), bSelected);
                              }
                         return TRUE;

                    case IDC_ADDLABEL:
                         GetDlgItemText(hDlg, IDC_LABELADDR, szText, 5);
                         sscanf(szText, "%X", &wAddr);
                         GetDlgItemText(hDlg, IDC_LABELTEXT, szText, 21);
                         strupr(szText);
                         wsprintf(szBuf, "%04X\t%s", wAddr, szText);
                         if ((iItem = LabelExist(hDlg, szBuf)) >= 0)
                              SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_DELETESTRING, iItem, 0);
                         SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_ADDSTRING, 0, (LPARAM) (LPCSTR) szBuf);
                         EnableWindow(GetDlgItem(hDlg, IDC_DELETELABEL), FALSE);
                         return TRUE;

                    case IDC_DELETELABEL:
                         iNbItem = (int) SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETCOUNT, 0, 0);
                         for (iItem = iNbItem - 1; iItem >= 0; iItem--)
                              if (SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETSEL, iItem, 0))
                                   SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_DELETESTRING, iItem, 0);
                         EnableWindow(GetDlgItem(hDlg, IDC_DELETELABEL), FALSE);
                         return TRUE;

                    case IDC_LABELADDR:
                    case IDC_LABELTEXT:
                         if (HIWORD(lParam) == EN_CHANGE)
                              {
                              bSelected = FALSE;
                              if (SendDlgItemMessage(hDlg, IDC_LABELADDR, WM_GETTEXTLENGTH, 0, 0) &&
                                 SendDlgItemMessage(hDlg, IDC_LABELTEXT, WM_GETTEXTLENGTH, 0, 0))
                                   bSelected = TRUE;
                              EnableWindow(GetDlgItem(hDlg, IDC_ADDLABEL), bSelected);
                              }
                         return TRUE;

                    case IDOK:
                         iNbItem = (int) SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETCOUNT, 0, 0);
                         if (iNbItem == 0)
                              {
                              if (lpLabelUser)
                                   MemoryFree(lpLabelUser);
                              lpLabelUser = NULL;
                              }
                         else {
                              iArray = 0;
                              if ((lpLabel = (char *) MemoryAlloc(LABEL_MEM_SIZE)) == NULL)
                                   {
                                   Error(hDlg, IDS_ERR_NO_LABEL_MEMORY, "Could not allocate memory for equates !");
                                   return TRUE;
                                   }
                              for (iItem = iNbItem - 1; iItem >= 0; iItem--)
                                   {
                                   SendDlgItemMessage(hDlg, IDC_LIST_LABEL, LB_GETTEXT, iItem, (LPARAM) (LPCSTR) szBuf);
                                   szBuf[4] = 0;
                                   sscanf(szBuf, "%X", &wAddr);
                                   *((WORD *) (lpLabel + iArray)) = wAddr;
                                   iArray += 2;
                                   *(lpLabel + iArray) = LABEL_FLAG_UNREFERENCED;
                                   iArray++;
                                   strcpy(lpLabel + iArray, szBuf + 5);
                                   iArray += strlen(szBuf + 5) + 1;
                                   if (iArray > MAX_BUF_LABEL)
                                        {
                                        Error(hDlg, IDS_ERR_LABEL_OVEFLOW, "Label overflow (too many labels) !");
                                        MemoryFree((BYTE *) lpLabel);
                                        return TRUE;
                                        }
                                   }
                              if (lpLabelUser)
                                   MemoryFree((BYTE *) lpLabelUser);
                              lpLabelUser = lpLabel;
                              }
                         EndDialog(hDlg, TRUE);
                         return TRUE;

                    case IDCANCEL:
                         EndDialog(hDlg, FALSE);
                         return TRUE;
                    }
               return TRUE;

          case WM_CTLCOLOR:

               /*
               ** change background color to gray.
               */
               if (HIWORD(lParam) == CTLCOLOR_STATIC || HIWORD(lParam) == CTLCOLOR_BTN || HIWORD(lParam) == CTLCOLOR_DLG)
                    {
                    SetBkColor((HDC) wParam, RGB(192, 192, 192));
                    return (BOOL) GetStockObject(LTGRAY_BRUSH);
                    }
               return FALSE;
          }
     return FALSE;
}

void LabelFreeCode(void)
{
     if (lpLabelCode)
          MemoryFree((BYTE *) lpLabelCode);
     if (lpLabelCodeNotUsed)
          MemoryFree((BYTE *) lpLabelCodeNotUsed);
     lpLabelCodeNotUsed = lpLabelCode = NULL;
}

void LabelFreeUser(void)
{
     if (lpLabelUser)
          MemoryFree(lpLabelUser);
     lpLabelUser = NULL;
}

void LabelInit(void)
{
     lpLabelUser = lpLabelSystem = NULL;
     lpLabelCode = NULL;
}

void LabelTerm(void)
{
     if (lpLabelSystem)
          MemoryFree(lpLabelSystem);
     lpLabelSystem = NULL;
     LabelFreeCode();
}

void LabelLoad(HANDLE hInstance, HWND hWnd)
{
     LabelTerm();
     DialogBox(hInstance, "LOADINGLABELBOX", hWnd, LabelLoadProc);
     DisRefresh(hMainWnd);
}

BOOL LabelUserLoad(HANDLE hInstance, HWND hWnd)
{
     /*
     ** ask the user for a filename.
     */
     if (GetFileName(hWnd, szEquPath,
                     OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
                     IDS_OPEN_USER_EQU,
                     "Equate files\0*.EQU\0All files\0*.*\0\0"))
          {
          LabelFreeUser();
          DialogBox(hInstance, "LOADINGUSERLABELBOX", hWnd, LabelUserLoadProc);
          DisRefresh(hMainWnd);
          return TRUE;
          }
     return FALSE;
}

void LabelUserSave(HANDLE hInstance, HWND hWnd)
{
int fd;
WORD iArray;
WORD wLen;
char *p;
char szBuf[128];

     if ((p = lpLabelUser) == 0)
          return;

     /*
     ** ask the user for a filename.
     */
     if (SaveFileName(hWnd, szEquPath,
                      OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT,
                      IDS_SAVE_USER_EQU,
                      "Equate files\0*.EQU\0All files\0*.*\0\0"))
          {
          if ((fd = open(szEquPath, _O_CREAT | _O_RDWR, _S_IREAD | _S_IWRITE)) < 0)
               Error(hWnd, IDS_ERR_WRITING_FILE, "Error while writing file %s", szEquPath);
          else {
               iArray = 0;
               while ((iArray < MAX_BUF_LABEL) && (*((WORD *) p)))
                    {
                    wsprintf(szBuf, "%s=$%04X\n", p + 3, *((WORD *) p));
                    write(fd, szBuf, strlen(szBuf));
                    wLen = strlen(p + 3) + 3 + 1;
                    iArray += wLen;
                    p += wLen;
                    }
               close(fd);
               }
          }
}

static BOOL LabelAskForReset(HWND hWnd)
{
char szAsk[256];

     if (lpLabelUser == 0)
          return FALSE;
     if (LoadString(hInst, IDS_ASK_USER_CLEAR, szAsk, sizeof(szAsk)) == 0)
          strcpy(szAsk, "Are you sure you want to clear all user symbols ?");
     if (MessageBox(hWnd, szAsk, szTitleApp, MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
          return TRUE;
     return FALSE;
}

BOOL LabelUserClear(HANDLE hInstance, HWND hWnd)
{
     if (! LabelAskForReset(hWnd))
          return FALSE;
     MemoryFree(lpLabelUser);
     lpLabelUser = NULL;
     return TRUE;
}

BOOL LabelUserEdit(HANDLE hInstance, HWND hWnd)
{
     return DialogBox(hInstance, "EDITLABEL", hWnd, LabelUserEditProc);
}

BOOL LabelAddCode(HWND hWnd, WORD wAddr, BOOL bCheckExist)
{
WORD iArray;
WORD *p;

     /*
     ** Address of 0 is not allowed as label. It is the NO_LABEL value !
     */
     if (wAddr == 0)
          return TRUE;

     /*
     ** if label exists in system or user equates, do not create a new one.
     */
     if (LabelReserveEquateInArray(lpLabelUser, wAddr, LABEL_FLAG_REFERENCED))
          return TRUE;
     if (bCheckExist)
          if (LabelReserveEquateInArray(lpLabelSystem, wAddr, LABEL_FLAG_REFERENCED))
               return TRUE;

     /*
     ** allocate label buffer if not done.
     */
     if (lpLabelCode == NULL)
          if ((lpLabelCode = (WORD *) MemoryAlloc(LABEL_MEM_SIZE)) == NULL)
               {
               Error(hMainWnd, IDS_ERR_NO_LABEL_MEMORY, "Could not allocate memory for equates !");
               return FALSE;
               }
     if (lpLabelCodeNotUsed == NULL)
          if ((lpLabelCodeNotUsed = (WORD *) MemoryAlloc(LABEL_MEM_SIZE)) == NULL)
               {
               MemoryFree((BYTE *) lpLabelCode);
               Error(hMainWnd, IDS_ERR_NO_LABEL_MEMORY, "Could not allocate memory for equates !");
               return FALSE;
               }

     /*
     ** browse label buffer to see if this address is not defined.
     */
     p = lpLabelCode;
     iArray = 0;
     while (iArray < (MAX_BUF_LABEL >> 1))
          {
          if (*p)
               {

               /*
               ** check if address not already defined.
               */
               if (*p++ == wAddr)
                    return TRUE;
               iArray++;
               }
          else {

               /*
               ** Add label definition to the label buffer.
               */
               *p++ = wAddr;
               *p = 0;
               return TRUE;
               }
          }
     Error(hWnd, IDS_ERR_LABEL_OVEFLOW, "Label overflow (too many labels) !");
     return FALSE;
}

/*
** sort label generated by disassembly.
*/
void LabelSortCode(void)
{
WORD iIndex;
WORD iArray;
WORD *p;
WORD wTmp;

     /*
     ** count how much labels we have.
     */
     if ((p = lpLabelCode) == NULL)
          return;
     iArray = 0;
     while (iArray < (MAX_BUF_LABEL >> 1))
          {
          if (*p++ == 0)
               break;
          else iArray++;
          }
     if (iArray < 2)
          return;

     /*
     ** sorting...
     */
     p = lpLabelCode;
     iIndex = 0;
     while (iIndex < iArray - 1)
          {
          if (*p > *(p + 1))
               {

               /*
               ** swap 2 WORDS
               */
               wTmp = *p;
               *p = *(p + 1);
               *(p + 1) = wTmp;
               if (iIndex > 0)
                    {
                    iIndex--;
                    p--;
                    }
               }
          else {
               iIndex++;
               p++;
               }
          }
     memcpy(lpLabelCodeNotUsed, lpLabelCode, LABEL_MEM_SIZE);
}

/*
** generate all code labels.
*/
BOOL LabelDumpCode(HWND hWnd)
{
WORD iArray;
WORD *p;
WORD wLen;
char *p2;

     if (p2 = lpLabelUser)
          {
          iArray = 0;
          while ((iArray < MAX_BUF_LABEL) && (*((WORD *) p2)))
               {
               if (*(p2 + 2) == LABEL_FLAG_REFERENCED)
                    if ((strchr(p2 + 3, '+') == NULL) && (strchr(p2 + 3, '-') == NULL))
                         if (! DisAddLabel(hWnd, p2 + 3, *((WORD *) p2), LABEL_USER))
                              return FALSE;
               wLen = strlen(p2 + 3) + 3 + 1;
               iArray += wLen;
               p2 += wLen;
               }
          }
     if (p = lpLabelCodeNotUsed)
          {

          /*
          ** add all code labels in disassembly listing.
          */
          iArray = 0;
          for (iArray = 0; iArray < (MAX_BUF_LABEL >> 1); iArray++, p++)
               if (*p)
                    {
                    wsprintf(szErr, "L%04X", *p);
                    if (! DisAddLabel(hWnd, szErr, *p, LABEL_CODE))
                         return FALSE;
                    }
          }
     return TRUE;
}

/*
** delete label from label defined buffer.
*/
void LabelDeleteCodeUsed(WORD wAddr)
{
WORD iArray;
WORD *p;

     if (p = lpLabelCodeNotUsed)
          {

          /*
          ** remove label reference to know which labels are to be defined as equates.
          */
          iArray = 0;
          for (iArray = 0; iArray < (MAX_BUF_LABEL >> 1); iArray++, p++)
               if (*p == wAddr)
                    {
                    *p = 0;
                    break;
                    }
          }
}

/*
** return label name in the code.
*/
static char *LabelFindCode(WORD wAddr)
{
WORD iArray;
WORD *p;
static char szLabel[10];

     if (p = lpLabelCode)
          {

          /*
          ** build label name with hex address.
          */
          iArray = 0;
          for (iArray = 0; iArray < (MAX_BUF_LABEL >> 1); iArray++)
               if (*p++ == wAddr)
                    {
                    wsprintf(szLabel, "L%04X", wAddr);
                    return szLabel;
                    }
          }
     return NULL;
}

/*
** find a label
*/
char *LabelFind(WORD wAddr)
{
char *lpLabel;
LABEL_FLAG bFlag;

     if (lpLabel = LabelFindCode(wAddr))
          return lpLabel;
     return LabelFindEquate(wAddr, &bFlag);
}

/*
** reserve a label
*/
char *LabelReserve(WORD wAddr)
{
char *lpLabel;

     if (lpLabel = LabelReserveEquateInArray(lpLabelUser, wAddr, LABEL_FLAG_DEFINED))
          return lpLabel;
     return LabelFindCode(wAddr);
}

/*
** save user labels to a file
*/
void LabelSaveUser(HWND hDlg, int fd)
{
     write(fd, &lpLabelUser, sizeof(lpLabelUser));
     if (lpLabelUser)
          write(fd, lpLabelUser, LABEL_MEM_SIZE);
}

/*
** restore user labels from a file
*/
void LabelRestoreUser(HWND hDlg, int fd)
{
char *lpUser;

     if (lpLabelUser)
          MemoryFree(lpLabelUser);
     lpLabelUser = NULL;
     read(fd, &lpUser, sizeof(lpUser));
     if (lpUser)
          {
          if ((lpLabelUser = (char *) MemoryAlloc(LABEL_MEM_SIZE)) == NULL)
               {
               Error(hDlg, IDS_ERR_NO_LABEL_MEMORY, "Could not allocate memory for equates !");
               lseek(fd, LABEL_MEM_SIZE, SEEK_CUR);
               }
          else read(fd, lpLabelUser, LABEL_MEM_SIZE);
          }
}
